﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System;
using PersonaLibrary.Data;

namespace PersonaLibrary.PrintViewModel.Model
{
	[Serializable]
	internal class Column : ReportItemParent
	{
		private bool _isVisible;

		public Column(string header)
		{
			Header = header;
			_isVisible = true;
		}

		

		public bool IsVisible
		{
			set { _isVisible = value; RisePropertyChanged("IsVisible"); }
			get { return _isVisible; }
		}

		public Border CellBorder
		{
			get
			{
				return new Border
				       	{
				       		BorderThickness = new Thickness(0.2),
							BorderBrush = Brushes.Black,
							Padding = new Thickness(1)
				       	};
			}
		}
	}

	[Serializable]
	internal class ReportItemParent : INotifyPropertyChanged
	{
		private double _size;
		private string _font;
		private int _bold;
		private double _width;
		[NonSerialized]
		private Func<Employee, object> _valueSelector;

		[NonSerialized]
		private GridLength? _gridWidth;

		public string Header { get; set; }

		public Func<Employee, object> ValueSelector
		{
			set { _valueSelector = value; RisePropertyChanged("ValueSelector"); }
			get { return _valueSelector; }
		}

		public GridLength Width
		{
			set
			{
				_gridWidth = value;
				_width = value.Value; 
				RisePropertyChanged("Width");
			}
			get
			{
				if(_gridWidth == null)
					_gridWidth = new GridLength(_width, GridUnitType.Star);

				return _gridWidth.Value;
			}
		}

		public double Size
		{
			set { _size = value; RisePropertyChanged("Size"); }
			get { return _size; }
		}

		public FontFamily Font
		{
			set { _font = value.Source; RisePropertyChanged("Font"); }
			get
			{
				if (_font == null)
					_font = "Arial";
				return new FontFamily(_font);
			}
		}

		public FontWeight Bold
		{
			set { _bold = value.ToOpenTypeWeight(); RisePropertyChanged("Bold"); }
			get
			{
				if (_bold == 0)
					_bold = 1;
				return FontWeight.FromOpenTypeWeight(_bold);
			}
		}

		public ICollection<FontFamily> Fonts
		{
			get { return System.Windows.Media.Fonts.SystemFontFamilies; }
		}

		[field: NonSerialized]
		public event PropertyChangedEventHandler PropertyChanged;

		protected void RisePropertyChanged(string name)
		{
			if(PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(name));
		}

		public override string ToString()
		{
			return Header;
		}
	}

	internal class ReportItemText : ReportItem
	{
		private string _text;
		private readonly ReportItemParent _parent;
		private Employee _employee;
		private readonly TextBox _control;

		public ReportItemText(ReportItemParent parent)
		{
			_parent = parent;
			_control = new TextBox();
			_parent.PropertyChanged += _parent_PropertyChanged;
			if(parent.Size != 0)
				_control.FontSize = parent.Size;
		}

		void _parent_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			switch (e.PropertyName)
			{
				case "Size":
					_control.FontSize = _parent.Size;
					break;
				case "Font":
					_control.FontFamily = _parent.Font;
					break;
				case "Bold":
					_control.FontWeight = _parent.Bold;
					break;
			} 
		}

		public string Text
		{
			set { _text = value; RisePropertyChanged("Text"); }
			get { return _text; }
		}
		
		public override FrameworkElement ToControl(Employee arg)
		{
			if (_employee != null)
				_employee.PropertyChanged -= arg_PropertyChanged;

			_employee = arg;
			
			if (_employee != null)
				_employee.PropertyChanged += arg_PropertyChanged;

			if (_parent.ValueSelector != null && string.IsNullOrEmpty(Text))
				_control.Text = Convert.ToString(_parent.ValueSelector.Invoke(arg));
			else
				_control.Text = Text;

			_control.BorderThickness = new Thickness(0);
			_control.Background = Brushes.Transparent;
			_control.TextWrapping = TextWrapping.Wrap;
			_control.TextAlignment = TextAlignment.Left;
			_control.AcceptsReturn = true;
			_control.AcceptsTab = true;

			return _control;
		}

		public FrameworkElement ToControl(Employee arg, string value)
		{
			if (_employee != null)
				_employee.PropertyChanged -= arg_PropertyChanged;

			_employee = arg;

			if (_employee != null)
				_employee.PropertyChanged += arg_PropertyChanged;

			_control.Text = value;

			_control.BorderThickness = new Thickness(0);
			_control.Background = Brushes.Transparent;
			_control.TextWrapping = TextWrapping.Wrap;
			_control.TextAlignment = TextAlignment.Left;
			_control.AcceptsReturn = true;
			_control.AcceptsTab = true;

			return _control;
		}

		void arg_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (_parent.ValueSelector != null && string.IsNullOrEmpty(Text))
			{
				ThreadHelper.SetValueToProperty(x => x.Text = Convert.ToString(_parent.ValueSelector.Invoke(_employee)), _control);
				//_control.Text = ;
			}
		}
	}

	internal abstract class ReportItem : INotifyPropertyChanged
	{
		public abstract FrameworkElement ToControl(Employee arg);

		public event PropertyChangedEventHandler PropertyChanged = delegate { };

		protected void RisePropertyChanged(string name)
		{
			PropertyChanged(this, new PropertyChangedEventArgs(name));
		}
	}
}
